package cn.schoolwow.flow.monitor.module.business.scheduleJob.definition.aware;

import cn.schoolwow.ams.domain.block.list.common.ListBlockButtonType;
import cn.schoolwow.ams.domain.block.list.dao.crud.DatabaseListBlockListListener;
import cn.schoolwow.ams.domain.block.list.dao.crud.DatabaseListBlockTableField;
import cn.schoolwow.ams.domain.block.list.dao.crud.DatabaseListBlockUpdateListener;
import cn.schoolwow.ams.domain.block.list.dao.entityTable.EntityTableListBlockConfigAware;
import cn.schoolwow.ams.domain.block.list.dao.entityTable.EntityTableListBlockOption;
import cn.schoolwow.ams.module.block.listBlock.common.domain.operation.ListBlockRequest;
import cn.schoolwow.flow.monitor.domain.FlowMonitorOption;
import cn.schoolwow.flow.monitor.entity.ScheduleJob;
import cn.schoolwow.flow.monitor.module.business.scheduleJob.definition.domain.ScheduleJobContext;
import cn.schoolwow.flow.monitor.module.business.scheduleJob.definition.flow.business.CancelScheduleJobFlow;
import cn.schoolwow.flow.monitor.module.business.scheduleJob.definition.flow.business.EnableScheduleJobFlow;
import cn.schoolwow.flow.monitor.module.business.scheduleJob.definition.flow.business.GetScheduleJobContextListFlow;
import cn.schoolwow.flow.monitor.module.business.scheduleJob.definition.flow.button.AddCancelScheduleJobButtonFlow;
import cn.schoolwow.flow.monitor.module.business.scheduleJob.definition.flow.button.AddEnableScheduleJobButtonFlow;
import cn.schoolwow.flow.monitor.module.business.scheduleJob.definition.flow.button.AddExecuteScheduleJobButtonFlow;
import cn.schoolwow.flow.monitor.module.business.scheduleJob.definition.flow.button.AddForceCancelScheduleJobFlow;
import cn.schoolwow.flow.monitor.module.common.domain.FlowMonitorConstant;
import cn.schoolwow.flow.monitor.module.common.flow.AddFlowCategoryNameCascadeRemoteSelectButton;
import cn.schoolwow.flow.monitor.module.common.flow.AddFlowNameRemoteSelectButton;
import cn.schoolwow.quickdao.domain.DAO;
import cn.schoolwow.quickdao.domain.database.dql.condition.Condition;
import cn.schoolwow.quickdao.domain.database.dql.response.PageVo;
import cn.schoolwow.quickflow.domain.FlowContext;
import cn.schoolwow.util.domain.query.instanceList.QueryInstanceList;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.support.CronExpression;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class ScheduleJobAware extends EntityTableListBlockConfigAware {
    @Autowired
    private ApplicationContext applicationContext;

    @Override
    public EntityTableListBlockOption getAMSBlockConfig() {
        EntityTableListBlockOption entityTableListBlockOption = new EntityTableListBlockOption(
                FlowMonitorConstant.PROJECT_NAME, "定时任务", FlowMonitorConstant.DAO_NAME, ScheduleJob.class);

        entityTableListBlockOption.listBlockShowOption.requestFieldNames = new String[]{
                "categoryName","name"
        };
        entityTableListBlockOption.listBlockShowOption.displayFieldNames = new String[]{
                "categoryName","name","cron","enable","createdAt","done","cancel"
        };
        entityTableListBlockOption.listBlockShowOption.updateDisplayFieldNames = new String[]{
                "categoryName","name","cron","enable","createdAt","done","cancel"
        };
        entityTableListBlockOption.listBlockShowOption.updateDisableFieldNames = new String[]{
                "categoryName","name","enable","createdAt","done","cancel"
        };
        entityTableListBlockOption.listBlockShowOption.listBlockButtonTypeArray = new ListBlockButtonType[]{
                ListBlockButtonType.UPDATE
        };

        setListListener(entityTableListBlockOption);
        setUpdateListener(entityTableListBlockOption);
        FlowMonitorOption flowMonitorOption = applicationContext.getBean(FlowMonitorOption.class);
        flowMonitorOption.flowMonitorQuickFlow.startFlow(new AddExecuteScheduleJobButtonFlow())
                .next(new AddEnableScheduleJobButtonFlow())
                .next(new AddCancelScheduleJobButtonFlow())
                .next(new AddForceCancelScheduleJobFlow())
                .putInstanceData(entityTableListBlockOption)
                .execute();

        flowMonitorOption.flowRecordQuickFlow.startFlow(new GetScheduleJobContextListFlow())
                .next(new AddFlowCategoryNameCascadeRemoteSelectButton())
                .next(new AddFlowNameRemoteSelectButton())
                .putInstanceData(entityTableListBlockOption)
                .execute();
        return entityTableListBlockOption;
    }

    private void setListListener(EntityTableListBlockOption entityTableListBlockOption){
        entityTableListBlockOption.databaseListBlockListener.listListener = new DatabaseListBlockListListener() {
            @Override
            public void beforeExecuteCondition(Condition condition, JSONObject queryCondition) throws Exception {
                if(queryCondition.containsKey("categoryName")){
                    String categoryName = queryCondition.getString("categoryName");
                    categoryName = categoryName.replace(",","-");
                    queryCondition.put("categoryName", categoryName);
                }
            }

            @Override
            public void afterExecuteCondition(Condition condition, JSONObject queryCondition, PageVo pageVo) throws Exception {
                JSONArray array = pageVo.getArray();
                if(null==array||array.isEmpty()){
                    return;
                }
                FlowMonitorOption flowMonitorOption = applicationContext.getBean(FlowMonitorOption.class);
                FlowContext flowContext = flowMonitorOption.flowMonitorQuickFlow.executeFlow(new GetScheduleJobContextListFlow());
                List<ScheduleJobContext> scheduleJobContextList = flowContext.getData("list", List.class);
                if(null==scheduleJobContextList||scheduleJobContextList.isEmpty()){
                    throw new IllegalArgumentException("定时任务上下文数据列表为空");
                }
                for(int i=0;i<array.size();i++){
                    JSONObject o = array.getJSONObject(i);
                    ScheduleJobContext scheduleJobContext = QueryInstanceList.newQuery(scheduleJobContextList)
                            .addQuery("categoryName", o.getString("categoryName"))
                            .addQuery("name", o.getString("name"))
                            .execute()
                            .checkOne();
                    o.put("running", null!=scheduleJobContext.scheduledFuture);
                    if(null!=scheduleJobContext.scheduledFuture){
                        o.put("done", scheduleJobContext.scheduledFuture.isDone());
                        o.put("cancel", scheduleJobContext.scheduledFuture.isCancelled());
                    }
                }
            }

            @Override
            public DatabaseListBlockTableField[] listTableFieldArray() {
                return new DatabaseListBlockTableField[]{
                        new DatabaseListBlockTableField("exist", "定时任务是否存在", "text", false),
                        new DatabaseListBlockTableField("done", "任务是否完成", "text", false),
                        new DatabaseListBlockTableField("cancel", "任务是否被取消", "text", false)
                };
            }
        };
    }

    private void setUpdateListener(EntityTableListBlockOption entityTableListBlockOption){
        entityTableListBlockOption.databaseListBlockListener.updateListener = new DatabaseListBlockUpdateListener<ScheduleJob>() {
            @Override
            public void update(DAO dao, ScheduleJob scheduleJob) throws Exception {
                //检查CRON表达式
                if(!CronExpression.isValidExpression(scheduleJob.getCron())){
                    throw new IllegalArgumentException("cron表达式不合法!当前值:"+scheduleJob.getCron());
                }
                dao.partColumn("cron").update(scheduleJob);

                if(scheduleJob.isEnable()){
                    FlowMonitorOption flowMonitorOption = applicationContext.getBean(FlowMonitorOption.class);
                    ListBlockRequest listBlockRequest = new ListBlockRequest();
                    listBlockRequest.row = JSON.parseObject(JSON.toJSONString(scheduleJob));
                    flowMonitorOption.flowMonitorQuickFlow.startFlow(new CancelScheduleJobFlow())
                            .next(new EnableScheduleJobFlow())
                            .putInstanceData(listBlockRequest)
                            .putTemporaryData("mayInterruptIfRunning", false)
                            .execute();
                }
            }
        };
    }
}
